package com.cencat.framework.security.service;

import com.cencat.common.exception.BusinessException;
import com.cencat.framework.security.model.LoginRequest;
import com.cencat.framework.security.model.LoginUser;
import com.cencat.framework.security.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * 认证服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthService {
    
    private final AuthenticationManager authenticationManager;
    private final TokenService tokenService;
    private final UserDetailsServiceImpl userDetailsService;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    
    /**
     * 用户登录
     */
    public LoginUser login(LoginRequest loginRequest) {
        String username = loginRequest.getUsername();
        // 获取密码用于后续认证处理
        String password = loginRequest.getPassword();
        
        try {
            // 验证用户名密码
            Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(username, password)
            );
            
            // 设置认证信息
            SecurityContextHolder.getContext().setAuthentication(authentication);
            
            // 获取用户详情
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            
            // 生成令牌
            String token = tokenService.createToken(loginUser);
            loginUser.setToken(token);
            
            // 记录登录日志
            recordLoginLog(loginUser, true, "登录成功");
            
            log.info("用户登录成功: username={}, userId={}", username, loginUser.getUserId());
            
            return loginUser;
            
        } catch (BadCredentialsException e) {
            // 记录登录失败日志
            recordLoginLog(null, false, "用户名或密码错误");
            throw new BusinessException("用户名或密码错误");
        } catch (Exception e) {
            // 记录登录失败日志
            recordLoginLog(null, false, "登录异常: " + e.getMessage());
            log.error("用户登录失败: username={}, error={}", username, e.getMessage());
            throw new BusinessException("登录失败，请稍后重试");
        }
    }
    
    /**
     * 用户注销
     */
    public void logout(String token) {
        try {
            // 删除令牌
            tokenService.deleteToken(token);
            
            // 清除安全上下文
            SecurityContextHolder.clearContext();
            
            log.debug("用户注销成功: token={}", token);
            
        } catch (Exception e) {
            log.error("用户注销失败: token={}, error={}", token, e.getMessage());
            throw new BusinessException("注销失败");
        }
    }
    
    /**
     * 刷新令牌
     */
    public LoginUser refreshToken(String token) {
        try {
            // 验证原令牌
            if (!jwtUtil.validateToken(token)) {
                throw new BusinessException("令牌无效");
            }
            
            // 获取用户信息
            LoginUser loginUser = tokenService.getLoginUser(token);
            if (loginUser == null) {
                throw new BusinessException("用户信息不存在");
            }
            
            // 刷新令牌
            tokenService.refreshToken(loginUser);
            
            // 生成新令牌
            String newToken = tokenService.createToken(loginUser);
            loginUser.setToken(newToken);
            
            log.debug("刷新令牌成功: userId={}", loginUser.getUserId());
            
            return loginUser;
            
        } catch (Exception e) {
            log.error("刷新令牌失败: token={}, error={}", token, e.getMessage());
            throw new BusinessException("刷新令牌失败");
        }
    }
    
    /**
     * 验证令牌
     */
    public boolean validateToken(String token) {
        return jwtUtil.validateToken(token);
    }
    
    /**
     * 注册用户
     */
    public LoginUser register(LoginRequest registerRequest) {
        String username = registerRequest.getUsername();
        String password = registerRequest.getPassword();
        
        try {
            // 检查用户名是否已存在
            if (userExists(username)) {
                throw new BusinessException("用户名已存在");
            }
            
            // 创建用户（这里应该调用用户服务创建用户）
            LoginUser loginUser = createUser(registerRequest);
            
            // 生成令牌
            String token = tokenService.createToken(loginUser);
            loginUser.setToken(token);
            
            log.info("用户注册成功: username={}, userId={}", username, loginUser.getUserId());
            
            return loginUser;
            
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("用户注册失败: username={}, error={}", username, e.getMessage());
            throw new BusinessException("注册失败，请稍后重试");
        }
    }
    
    /**
     * 修改密码
     */
    public void changePassword(String username, String oldPassword, String newPassword) {
        try {
            // 验证旧密码
            LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(username);
            if (!passwordEncoder.matches(oldPassword, loginUser.getPassword())) {
                throw new BusinessException("原密码错误");
            }
            
            // 更新密码（这里应该调用用户服务更新密码）
            updateUserPassword(loginUser.getUserId(), newPassword);
            
            log.info("修改密码成功: username={}", username);
            
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("修改密码失败: username={}, error={}", username, e.getMessage());
            throw new BusinessException("修改密码失败");
        }
    }
    
    /**
     * 重置密码
     */
    public void resetPassword(String username, String newPassword) {
        try {
            // 重置密码（这里应该调用用户服务重置密码）
            updateUserPasswordByUsername(username, newPassword);
            
            log.info("重置密码成功: username={}", username);
            
        } catch (Exception e) {
            log.error("重置密码失败: username={}, error={}", username, e.getMessage());
            throw new BusinessException("重置密码失败");
        }
    }
    
    /**
     * 记录登录日志
     */
    private void recordLoginLog(LoginUser loginUser, boolean success, String message) {
        try {
            // 这里应该调用日志服务记录登录日志
            log.info("登录日志: username={}, success={}, message={}", 
                loginUser != null ? loginUser.getUsername() : "unknown", 
                success, message);
        } catch (Exception e) {
            log.error("记录登录日志失败: {}", e.getMessage());
        }
    }
    
    /**
     * 检查用户是否存在
     */
    private boolean userExists(String username) {
        try {
            userDetailsService.loadUserByUsername(username);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 创建用户（模拟实现）
     */
    private LoginUser createUser(LoginRequest registerRequest) {
        // 这里应该调用用户服务创建用户
        // 为了演示，这里创建一个模拟用户
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(System.currentTimeMillis());
        loginUser.setUsername(registerRequest.getUsername());
        loginUser.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
        loginUser.setRealName("新用户");
        loginUser.setEmail(registerRequest.getUsername() + "@cencat.com");
        loginUser.setTenantId(1L);
        loginUser.setStatus(1);
        
        return loginUser;
    }
    
    /**
     * 更新用户密码（模拟实现）
     */
    private void updateUserPassword(Long userId, String newPassword) {
        // 这里应该调用用户服务更新密码
        log.debug("更新用户密码: userId={}", userId);
    }
    
    /**
     * 根据用户名更新密码（模拟实现）
     */
    private void updateUserPasswordByUsername(String username, String newPassword) {
        // 这里应该调用用户服务重置密码
        log.debug("重置用户密码: username={}", username);
    }
}